#--
# Copyright (c) 2007 Maximilian Ott
# 
# Permission is hereby granted, free of charge, to any person obtaining a copy
# of this software and associated documentation files (the "Software"), to deal
# in the Software without restriction, including without limitation the rights
# to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
# copies of the Software, and to permit persons to whom the Software is
# furnished to do so, subject to the following conditions:
# 
# The above copyright notice and this permission notice shall be included in
# all copies or substantial portions of the Software.
# 
# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL THE
# AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
# OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
# THE SOFTWARE.
#++
#
# Define common methods for all models
# 

require 'models/document'

#class WBaseModel < ActiveRecord::Base
module WBaseModel 
  
  # included() gets executed anytime this module is included into an object.  
  # The object is passed as an argument to included().
  class << self
    def included(target)
      target.extend ClassMethods
    end
  end

  module ClassMethods  
  
    def belongs_to(association_id, options = {})
      reflection = create_belongs_to_reflection(association_id, options)
      define_method(reflection.name.to_s + '_class') do
        reflection.klass
      end
      super
    end
    
    def has_many(association_id, options = {})
      reflection = create_has_many_reflection(association_id, options)
      define_method(reflection.name.to_s + '_class') do
        reflection.klass
      end
      super
      
      self.class_eval "alias set_#{association_id} #{association_id}=" 
      define_method "#{association_id}=" do |aa|
        klass = reflection.klass
        name = association_id
    
        if aa.kind_of? Hash
    #      @a = aa; breakpoint
          # TODO: should be sorted
          aa.values.each do |attr|
            puts "ATTR >>> #{attr} ID >>> #{id}:#{id.class}"
            id = attr[:id]
            r = (id.nil? || id.empty?) ? klass.new : klass.find(id)
            r.update_attributes(attr)
    #        @r = r; breakpoint
            self.send(name) << r
          end
        else
          self.send('set_' + name.to_s, aa)
        end
      end
      
    end
    
    # Create a relationship with the document class. This will also overload the
    # +doc_id=+ method to process an upload field and turn it into a linked document.
    #
    def has_many_documents(doc_id, options = {})
      self.has_many doc_id, options.reverse_merge(:foreign_key => 'reference_id', :order => 'position DESC')
  
      class_name = options[:class_name] || doc_id.singularize.capitalize.gsub(/_(.)/) do |s| $1.capitalize end
      klass = eval(class_name.to_s) # TODO: There should be a cleaner way to find the actual class
      
      
#      self.class_eval "alias set_#{doc_id} #{doc_id}="  # research_proposals=
  
#      define_method "#{doc_id}=" do |rp|
#    #    @r = rp; breakpoint
#    
#        if rp.nil? || rp.kind_of?(String)
#          raise 'Illegal file name.'
#          return
#        end
#        if rp.respond_to?(:content_type)
#          rp = klass.init_from_upload(rp) #, :student_id => self.id)
#          self.send(doc_id) << rp
#          rp.dump_meta # create an additiona file in case we loose the database
#    #      @s = self; @d = rp; breakpoint
#        else
#          self.send('set_' + doc_id.to_s, rp)
#        end
#      end

      define_method "add_#{doc_id.to_s.singularize}" do |d|
        if d.kind_of? Hash
          d = klass.new(d)
        end
        self.send(doc_id) << d
      end
      
    end
  end
end
